import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Vector;

public class AuthorParser extends RawDumpParser {
  HashSet<String> newAuthors_ = new HashSet<String>();
  Vector<Author> authors_;
  HashMap<String, Integer> nameToIndex_;

  int numAuthors_;
  int newId_;

  int numValidAuthors_;
  int numDegZeroAuthors_;
  int limit_;
  
  public AuthorParser(int limit) {
    authors_ = new Vector<Author>();
    nameToIndex_ = new HashMap<String, Integer>();
    numAuthors_ = 0;
    newId_ = 10000;
    
    limit_ = limit;
    
    
    parseClusterRun();
  }
  
  public void parseClusterRun() {
    try {
      FileReader fr = new FileReader(CoAuthorNetwork.COMMUNITY_NET_FILE);
      BufferedReader in = new BufferedReader(fr);
      
      String line;
      
      while (true) {
        line = in.readLine();
        
        if (line == null) {
          break;
        }
        
        int quote_start = line.indexOf('"');
        
        if (quote_start < 0) {
          continue;
        }

        int quote_end = line.indexOf('"', quote_start+1);
        String id_name_str = line.substring(quote_start+1, quote_end);
        
        
        int id_start = id_name_str.indexOf('[') + 1;
        int id_end = id_name_str.indexOf(']', id_start);
        
        int id = Integer.parseInt(id_name_str.substring(id_start, id_end));
        
        String name = id_name_str.substring(id_end + 1);
        Author at = new Author(id, name);
        
        authors_.add(at);
        nameToIndex_.put(name, numAuthors_++);
      }
    } catch (IOException ie) {
      ie.printStackTrace();
    } catch (NumberFormatException ne) {
      ne.printStackTrace();
    }
  }
  
  public void parseAuthors() {
    for (int i = getNumRawFiles() - 1; i >= 0; --i) {
      String rFileName = getRawFileName(i);
      
      XMLHandler xmlh = new XMLHandler(rFileName, limit_);
      
      try {
        xmlh.updateAuthorTimestamp(this);
      } catch (Exception e) {
        String err = "";
        err += "Parsing Error :";
        err += " File: " + rFileName;
        err += " Record: " + xmlh.getCurrentRecord();
        
        System.err.println(err);

        e.printStackTrace();
        System.exit(0);
      }
    }
  }
  
  public Integer updateTimestampForAuthor(String key, String ts, String docid) throws IOException {
    Integer i = nameToIndex_.get(key);
    Author a = null;
    
    if (i == null) {
      a = new Author(newId_++, key);
      
      authors_.add(a);
      nameToIndex_.put(key, numAuthors_);
      
      i = numAuthors_++;
    } else {
      a = authors_.get(i);
    }
    
    a.updateDateStamp(ts);
    return i;
  }
  
  public void addNeighborsForRecord(Vector<Integer> neighbors, String ts) {
    for (int i = 0; i < neighbors.size(); ++i) {
      Author a = authors_.get(neighbors.get(i));
      
      for (int j = 0; j < neighbors.size(); ++j) {
        Author nbr = authors_.get(neighbors.get(j));
        a.addNeighbor(nbr.getAuthorId());
      }
    }
  }
  
  public void process(CoAuthorNetwork.SortParam sp) {
//    Iterator<Map.Entry<String, Author>> it = authorInfo_.entrySet().iterator();
//    int count = 0;
//    while (it.hasNext()) {
//      Map.Entry<String, Author> entry = it.next();
//      
//      Author a = entry.getValue();
//      authors_.add(a);
//      
//      if (a.getDateStamp() < 0) {
//        count++;
//        System.out.println("Author timestamp not found: " + a.getName());
//      } else {
//        System.out.println("");
//      }
//    }

    switch (sp) {
    case DATESTAMP:
      Collections.sort(authors_, new Author.AuthorDateComparator());
      break;
    case DEGREE:
      Collections.sort(authors_, new Author.AuthorDegreeComparator());
      break;
    default:
      System.err.println("Something went wrong.");
      break;
    }

    numValidAuthors_ = 0;
    numDegZeroAuthors_ = 0;
    for (int i = 0; i < authors_.size(); ++i) {
      Author a = authors_.get(i);
      
      if (a.isValid()) {
        if (a.getDegree() == 0) numDegZeroAuthors_++;

        numValidAuthors_++;
      }
    }
    
    System.out.println(numAuthors_ + " : " + numValidAuthors_);
  }
  
  public void writeDateStampToFile(String fileName) throws IOException {
    FileWriter fw = new FileWriter(fileName);
    PrintWriter out = new PrintWriter(fw);
    
    HashSet<Integer> id = new HashSet<Integer>();
    
    for (int ai = 0; ai < authors_.size(); ++ai) {
      Author a = authors_.get(ai);
      
      if (id.contains(a.getAuthorId())) System.err.println(a.toString());

      if (a.isValid()) {
        out.println(a.toString());
      }
      
      id.add(a.getAuthorId());
    }
    
    out.close();
    fw.close();
  }
  
  public void dumpDegreeDistr(String fileName) throws IOException {
    FileWriter fw = new FileWriter(fileName);
    PrintWriter out = new PrintWriter(fw);
    
//    HashSet<Integer> id = new HashSet<Integer>();
    
    out.println(numValidAuthors_ + " " + numDegZeroAuthors_);
    for (int ai = 0; ai < authors_.size(); ++ai) {
      Author a = authors_.get(ai);
      
//      if (id.contains(a.getAuthorId())) System.err.println(a.toString());

      if (a.isValid()) {
        out.println(a.toString());
      }
      
//      id.add(a.getAuthorId());
    }
    
    out.close();
    fw.close();
  }
}